#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "AWLocalViewport.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWScenario.h"
#include "AWSelectScenario.h"
#include "AWBody.h"
#include "AWSensor.h"
#include "AWBrain.h"
#include "AWAgent.h"
#include "AWWorld.h"
#include "AWSelectWorld.h"

#include "loader.h"

extern int SCREEN_DX,SCREEN_DY;

AW_SelectWorld::AW_SelectWorld() : AW_World() 
{
	class_name->set("AW_SelectWorld");

	camera_moving=false;
	SelectedAgent=0;
	desired_SelectedAgent=0;

} /* AW_SelectWorld::AW_SelectWorld */ 


AW_SelectWorld::AW_SelectWorld(FILE *fp) : AW_World()
{
	class_name->set("AW_SelectWorld");

	camera_moving=false;
	SelectedAgent=0;
	desired_SelectedAgent=0;

	load(fp);
} /* AW_SelectWorld::AW_SelectWorld */ 


AW_SelectWorld::~AW_SelectWorld()
{
	if (SelectedAgent!=0) delete SelectedAgent;
	if (desired_SelectedAgent!=0) delete desired_SelectedAgent;
} /* AW_SelectWorld::~AW_SelectWorld */ 


bool AW_SelectWorld::load(FILE *fp) 
{
	if (!AW_World::load(fp)) return false;


	return true;
} /* AW_SelectWorld::load */ 


bool AW_SelectWorld::save(FILE *fp) 
{
	if (!AW_World::save(fp)) return false;


	return true;
} /* AW_SelectWorld::save */ 


bool AW_SelectWorld::is_a(char *c)
{
	if (strcmp(c,"AW_SelectWorld")==0) return true;

	return AW_World::is_a(c);
} /* AW_SelectWorld::is_a */ 


bool AW_SelectWorld::is_a(Symbol *c)
{
	if (c->cmp("AW_SelectWorld")) return true;

	return AW_World::is_a(c);
} /* AW_SelectWorld::is_a */ 



void AW_SelectWorld::beforedraw(void)
{
	if (camera_moving) {
		long current=GetTickCount();
		double t=(current-camera_move_start)/1000.0;
		if (t>=1.0) {
			camera=desired_camera;
			camerap=desired_camerap;
			camera_moving=false;
			if (desired_SelectedAgent!=0) {
				if (SelectedAgent!=0) delete SelectedAgent;
				SelectedAgent=desired_SelectedAgent;
				desired_SelectedAgent=0;
			} /* if */ 
		} else {
			camera.x=camera_move_A.x*t*t+camera_move_B.x*t+camera_move_C.x;
			camera.y=camera_move_A.y*t*t+camera_move_B.y*t+camera_move_C.y;
			camera.z=camera_move_A.z*t*t+camera_move_B.z*t+camera_move_C.z;

			camerap.x=camerap_move_A.x*t*t+camerap_move_B.x*t+camerap_move_C.x;
			camerap.y=camerap_move_A.y*t*t+camerap_move_B.y*t+camerap_move_C.y;
			camerap.z=camerap_move_A.z*t*t+camerap_move_B.z*t+camerap_move_C.z;
		} /* if */ 
	} /* if */ 

	AW_World::beforedraw();
} /* AW_SelectWorld::beforedraw */ 


void AW_SelectWorld::draw_world(void)
{
	AW_Agent *a,*local_agent=0;
	int name=0;

	if (scn->is_a("AW_SelectScenario")) {
		((AW_SelectScenario *)scn)->selection_first_name(0);
		scn->draw();
		name=((AW_SelectScenario *)scn)->selection_get_num();
	} else {
		scn->draw();
	} /* if */ 

	Agents.Rewind();
	while(Agents.Iterate(a)) {
		if (SelectedAgent!=0 && SelectedAgent->cmp(a->get_AgentName())) {
            local_agent=a;
		} else {
			glPushName(name);
			a->draw();
			glPopName();
		} /* if */ 
		name++;
	} /* while */ 
        
    if (local_agent!=0) local_agent->localdraw();

} /* AW_SelectWorld::draw */ 


bool AW_SelectWorld::KeyboardEvent(int key)
{
	if (SelectedAgent!=0) {
		List<AW_Agent> l;
		AW_Agent *a;

		l.Instance(Agents);
		l.Rewind();
		while(l.Iterate(a)) {
			if (SelectedAgent->cmp(a->get_AgentName())) {
				if (a->KeyboardEvent(key)) return true;
			} /* if */ 
		} /* while */ 
	} /* if */ 

	return false;
} /* AW_SelectWorld::KeyboardEvent */ 


bool AW_SelectWorld::MouseClick(int x,int y)
{
	GLuint buffer[1024];
	GLint viewport[4];
	unsigned int hits;
	float fAspect;

	if (SelectedAgent!=0) {
		List<AW_Agent> l;
		AW_Agent *a;

		l.Instance(Agents);
		l.Rewind();
		while(l.Iterate(a)) {
			if (SelectedAgent->cmp(a->get_AgentName())) {
				if (a->MouseClick(x,y)) return true;
			} /* if */ 
		} /* while */ 
	} /* if */ 

	glSelectBuffer(1024,buffer); 

	glRenderMode(GL_SELECT);

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glGetIntegerv(GL_VIEWPORT,viewport);
	gluPickMatrix(x,viewport[3]-y,3,3,viewport);

	if (SCREEN_DY!=0) fAspect = (float)SCREEN_DX/SCREEN_DY;
				 else fAspect = 1.0f;
		
	gluPerspective(45.0f, fAspect, 0.1F, 100);
	gluLookAt(camera.x,camera.y,camera.z,camerap.x,camerap.y,camerap.z,0,-1,0);
	
	glMatrixMode(GL_MODELVIEW);
	glInitNames();

	/* Draw the world (excluding the local-agent draw): */ 
	{
		AW_Agent *a;
		int name=0;

		if (scn->is_a("AW_SelectScenario")) {
			((AW_SelectScenario *)scn)->selection_first_name(0);
			scn->draw();
			name=((AW_SelectScenario *)scn)->selection_get_num();
		} else {
			scn->draw();
		} /* if */ 

		Agents.Rewind();
		while(Agents.Iterate(a)) {
			if (SelectedAgent==0 || !SelectedAgent->cmp(a->get_AgentName())) {
				glPushName(name);
				a->draw();
				glPopName();
			} /* if */ 
			name++;
		} /* while */ 
	}

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	hits = glRenderMode(GL_RENDER);
	if (hits>0) {
		unsigned int i;
		GLuint names, *ptr, minZ,*ptrNames=0, numberOfNames=0;

		ptr = (GLuint *) buffer;
		minZ = 0xffffffff;
		for (i = 0; i < hits; i++) {	
			names = *ptr;
			ptr++;
			if (*ptr < minZ) {
			numberOfNames = names;
			minZ = *ptr;
			ptrNames = ptr+2;
			} /* if */ 

			ptr += names+2;
		} /* for */ 

		ptr = ptrNames;

		if (numberOfNames>0) {
			int sel=*ptr;

			select(sel);
			return true;
		} else {
			select(-1);
		} /* if */ 
	} else {
		select(-1);
	} /* if */ 

	return false;
} /* AW_SelectWorld::MouseClick */ 


void AW_SelectWorld::select(int sel)
{
	int first_agent=0;
	bool new_position=false;

	if (SelectedAgent!=0) delete SelectedAgent;
	if (desired_SelectedAgent!=0) delete desired_SelectedAgent;
	SelectedAgent=0;
	desired_SelectedAgent=0;
	desired_camera=initial_camera;
	desired_camerap=initial_camerap;
	new_position=true;

	if (scn->is_a("AW_SelectScenario")) {
		float x,y,z,xp,yp,zp;

		first_agent=((AW_SelectScenario *)scn)->selection_get_num();
		if (((AW_SelectScenario *)scn)->set_selected(sel,&x,&y,&z,
														 &xp,&yp,&zp)) {
			if (SelectedAgent!=0) delete SelectedAgent;
			if (desired_SelectedAgent!=0) delete desired_SelectedAgent;

			desired_camera.x=x;
			desired_camera.y=y;
			desired_camera.z=z;
			desired_camerap.x=xp;
			desired_camerap.y=yp;
			desired_camerap.z=zp;
			new_position=true;
		} /* if */ 

	} /* if */ 

	if (sel>=first_agent) {
		int sela=sel-first_agent;

		if (sela<Agents.Length()) {
			Vector pos,dir;

			if (SelectedAgent!=0) delete SelectedAgent;
			if (desired_SelectedAgent!=0) delete desired_SelectedAgent;
			SelectedAgent=0;
			desired_SelectedAgent=0;

			desired_SelectedAgent=new Symbol(Agents[sela]->get_AgentName());
			pos=Agents[sela]->get_pos();
			dir=Agents[sela]->get_dir();

			desired_camera.x=pos.x;
			desired_camera.y=pos.y-1.0;
			desired_camera.z=pos.z;
			desired_camerap.x=pos.x+2*dir.x;
			desired_camerap.y=pos.y-1.0;
			desired_camerap.z=pos.z+2*dir.z;
			new_position=true;
		} /* if */ 

	} /* if */ 


	if (new_position) {
		camera_moving=true;
		camera_move_start=GetTickCount();
		camera_move_end=camera_move_start+1000;

		/* compute camera movement equations: */ 
		{
			double matrix[9]={0, 0,	1,
							  1, 1,	1,
							  2, 1,	0};
			double independent[3]={camera.x,desired_camera.x,0};
			double sol[3]={0,0,0};
			kramer_d(matrix,independent,sol);
			camera_move_A.x=sol[0];
			camera_move_B.x=sol[1];
			camera_move_C.x=sol[2];
		}
		{
			double matrix[9]={0, 0,	1,
							  1, 1,	1,
							  2, 1,	0};
			double independent[3]={camera.y,desired_camera.y,0};
			double sol[3]={0,0,0};
			kramer_d(matrix,independent,sol);
			camera_move_A.y=sol[0];
			camera_move_B.y=sol[1];
			camera_move_C.y=sol[2];
		}
		{
			double matrix[9]={0, 0,	1,
							  1, 1,	1,
							  2, 1,	0};
			double independent[3]={camera.z,desired_camera.z,0};
			double sol[3]={0,0,0};
			kramer_d(matrix,independent,sol);
			camera_move_A.z=sol[0];
			camera_move_B.z=sol[1];
			camera_move_C.z=sol[2];
		}

		{
			double matrix[9]={0, 0,	1,
							  1, 1,	1,
							  2, 1,	0};
			double independent[3]={camerap.x,desired_camerap.x,0};
			double sol[3]={0,0,0};
			kramer_d(matrix,independent,sol);
			camerap_move_A.x=sol[0];
			camerap_move_B.x=sol[1];
			camerap_move_C.x=sol[2];
		}
		{
			double matrix[9]={0, 0,	1,
							  1, 1,	1,
							  2, 1,	0};
			double independent[3]={camerap.y,desired_camerap.y,0};
			double sol[3]={0,0,0};
			kramer_d(matrix,independent,sol);
			camerap_move_A.y=sol[0];
			camerap_move_B.y=sol[1];
			camerap_move_C.y=sol[2];
		}
		{
			double matrix[9]={0, 0,	1,
							  1, 1,	1,
							  2, 1,	0};
			double independent[3]={camerap.z,desired_camerap.z,0};
			double sol[3]={0,0,0};
			kramer_d(matrix,independent,sol);
			camerap_move_A.z=sol[0];
			camerap_move_B.z=sol[1];
			camerap_move_C.z=sol[2];
		}
	} /* if */ 

} /* AW_SelectWorld::select */ 



void AW_SelectWorld::select(char *name)
{
	int first_agent=0;
	List<AW_Agent> l;
	AW_Agent *a;

	if (scn->is_a("AW_SelectScenario")) {
		first_agent=((AW_SelectScenario *)scn)->selection_get_num();
	} /* if */ 

	l.Instance(Agents);
	l.Rewind();
	while(l.Iterate(a)) {
		if (strcmp(a->get_AgentName()->get(),name)==0) {
			select(Agents.PositionRef(a)+first_agent);
			return;
		} /* if */ 
	} /* while */ 

	select(-1);
} /* AW_SelectWorld::select */ 



